package OOP2;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;


//面向抽象编程的本质就是：
//    上层代码只定义规范（例如：abstract class Person）；
//    不需要子类就可以实现业务逻辑（正常编译）；
//    具体的业务逻辑由不同的子类实现，调用者并不关心。

//抽象类的产生：
//    父类Person的run()方法没有实际意义，但无法去掉方法的执行语句，无法去掉方法的定义
//    如果父类的方法本身不需要实现任何功能，仅仅是为了定义方法签名，目的是让子类去覆写它，那么，可以把父类的方法声明为抽象方法
//    抽象类无法执行，也无法被实例化；必须通过非抽象子类实例化。子类必须实现抽象类中的所有抽象方法，普通方法不用
//    且必须声明abstract，否则无法编译


/**
 * 抽象类与接口综合演示
 * 核心概念：
 * 1. 抽象类的定义与继承
 * 2. 接口的多实现机制
 * 3. 默认方法的实际应用
 * 4. 面向抽象编程实践
 */
public class AbstractClassDemo {

    // ==================== 抽象类示例 ====================
    abstract static class AbstractPerson {
        protected String name;

        public AbstractPerson(String name) {
            this.name = Objects.requireNonNull(name, "姓名不能为空");
        }

        /**
         * 抽象方法：定义移动行为规范
         */
        public abstract void move();

        /**
         * 具体方法：公共行为实现
         */
        public void introduce() {
            System.out.println("我是：" + name);
        }
    }

    static class Student extends AbstractPerson {
        private final String studentId;

        public Student(String name, String studentId) {
            super(name);
            this.studentId = studentId;
        }

        // 子类必须实现抽象类中的所有抽象方法，普通方法不用
        @Override
        public void move() {
            System.out.println(name + "快步走向教室");
        }
    }

    static class Teacher extends AbstractPerson {
        public Teacher(String name) {
            super(name);
        }

        @Override
        public void move() {
            System.out.println(name + "从容走向讲台");
        }
    }

    // ==================== 接口示例 ====================


    // 接口:如果一个抽象类没有字段，所有方法全部都是抽象方法
    // 接口：实现类必须实现接口中的所有抽象方法，但可以选择性地重写 default 方法。
    // 因为接口定义的所有方法默认都是public abstract的，所以这两个修饰符不需要写出来（写不写效果都一样）
    public abstract interface Movable {
        /**
         * 定义移动速度规范
         * @return 速度值（km/h）
         */
        public abstract double getSpeed();
    }

    interface Eatable {
        /**
         * 定义能量值规范
         * @return 千卡数
         */
        int getCalories();
    }

    // 一个类只能继承自另一个类，不能从多个类继承。
    // 但是，一个类可以implements实现多个interface
    // ==================== 多接口实现示例 ====================
    static class FarmPig implements Movable, Eatable {
        private final String name;
        private double weight;

        public FarmPig(String name, double weight) {
            this.name = name;
            this.weight = weight;
        }

        @Override
        public double getSpeed() {
            return 5.2 * (1 - weight / 200); // 体重影响速度
        }

        @Override
        public int getCalories() {
            return (int) (weight * 3300); // 每公斤3300千卡
        }
    }

    // 接口extends继承，它相当于扩展了接口的方法
    // ==================== 接口继承示例 ====================
    interface Livable extends Movable, Eatable {
        /**
         * 定义生存环境温度范围
         * @return 适宜温度范围
         */
        String getComfortTemperatureRange();
    }

    // JDK>=1.8后，接口中可定义default方法，实现类可以不必覆写default方法
    // default方法和抽象类的普通方法是有所不同的。因为interface没有字段，default方法无法访问字段，而抽象类的普通方法可以访问实例字段。
    // ==================== 默认方法示例 ====================
    interface Loggable {
        default String getLogHeader() {
            return "日志记录：" + LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
        }

        /**
         * 定义日志格式规范
         */
        String toLogString();
    }

    static class FarmPigWithLog extends FarmPig implements Loggable {
        public FarmPigWithLog(String name, double weight) {
            super(name, weight);
        }

        @Override
        public String toLogString() {
            return String.format("%s | 体重: %.1fkg | 速度: %.1fkm/h | 能量: %,d千卡",
                    getLogHeader(), super.weight, getSpeed(), getCalories());
        }
    }

    // ==================== 使用示例 ====================
    public static void main(String[] args) {
        // 抽象类多态演示
        // 面向抽象编程：尽量引用高层类型，避免引用实际子类型的方式
        AbstractPerson[] people = {
                new Student("张三", "S1001"),
                new Teacher("王老师")
        };

        for (AbstractPerson person : people) {
            person.introduce();
            person.move();
            System.out.println("------------");
        }

        // 接口多实现演示
        FarmPig pig = new FarmPig("大白", 150.5);
        System.out.printf("%s 移动速度：%.1fkm/h%n", pig.name, pig.getSpeed());
        System.out.printf("可提供能量：%,d 千卡%n", pig.getCalories());

        // 默认方法演示
        FarmPigWithLog loggedPig = new FarmPigWithLog("小花", 120.8);
        System.out.println(loggedPig.toLogString());
    }
}